package br.com.rapidrest.ioc;

import java.lang.reflect.Field;

import javax.servlet.http.HttpSession;

import br.com.rapidrest.annotation.SessionContext;
import br.com.rapidrest.chain.BasicChainContext;
import br.com.rapidrest.exception.InjectionException;

public class SessionContextFieldHandler implements FieldHandler {

	private static final String SESSION_CONTEXT_FIELD_PREFIX = "rapidrest.context.stored.field";

	@Override
	public void handle(Field field, Object target, BasicChainContext context)
			throws InjectionException {
		if (isSessionContextStored(field)) {
			try {
				HttpSession session = context.getRequest().getSession();
				Object fieldValue = retrieveFromSession(field, target, session);

				SessionContext sessionContext = field
						.getAnnotation(SessionContext.class);
				if (sessionContext.create() && fieldValue == null) {
					Class<?> declaringClass = field.getDeclaringClass();
					fieldValue = declaringClass.newInstance();
				}

				field.setAccessible(true);
				field.set(target, fieldValue);
			} catch (IllegalArgumentException e) {
				throw new InjectionException(e);
			} catch (IllegalAccessException e) {
				throw new InjectionException(e);
			} catch (InstantiationException e) {
				throw new InjectionException(e);
			}
		}
	}

	protected boolean isSessionContextStored(Field field) {
		return field.isAnnotationPresent(SessionContext.class);
	}

	protected Object retrieveFromSession(Field field, Object target,
			HttpSession session) {
		Class<?> declaringClass = field.getDeclaringClass();
		String sessionKey = SESSION_CONTEXT_FIELD_PREFIX + "."
				+ declaringClass.getName();
		return session.getAttribute(sessionKey);
	}

	@Override
	public void end(Field field, Object target, BasicChainContext context)
			throws InjectionException {
		if (isSessionContextStored(field)) {
			try {
				HttpSession session = context.getRequest().getSession();
				field.setAccessible(true);
				Object fieldValue = field.get(target);

				Class<?> declaringClass = field.getDeclaringClass();
				String sessionKey = SESSION_CONTEXT_FIELD_PREFIX + "."
						+ declaringClass.getName();

				session.setAttribute(sessionKey, fieldValue);
			} catch (IllegalArgumentException e) {
				throw new InjectionException(e);
			} catch (IllegalAccessException e) {
				throw new InjectionException(e);
			}
		}
	}

}
